// Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef NET_COMM_H
#define NET_COMM_H

#include <mutex>
#include <array>

#include "Include/msghead.h"
#include "Log/logging.h"
#include "Communication/Socket/VmiSocket.h"
#include "Communication/Heartbeat/Heartbeat.h"
#include "Communication/StreamParse/StreamParser.h"
#include "Communication/PacketHandle/PacketHandle.h"
#include "Communication/MsgFragment/MsgFragment.h"
#include "Communication/Include/CommApi.h"

enum NetCommStatus {
    NET_COMM_STATUS_UNINIT = 0,  // 未初始化
    NET_COMM_STATUS_INIT = 1,    // 已初始化
    NET_COMM_STATUS_RUNNING = 2, // 运行
};

class NetComm;

class ClientNotice : public VmiEventNotice {
public:
    /**
     * @功能描述：clientNotice构造函数
     */
    explicit ClientNotice(NetComm *netComm);

    ClientNotice() = delete;

    /**
     * @功能描述：clientNotice析构函数
     */
    ~ClientNotice() override;

    /**
     * @功能描述：客户端Socket断开通知函数
     * @参数 [in] tcpSocket：客户端socket对象
     */
    void Notice(std::shared_ptr<VmiSocket> tcpSocket) override;

private:
    NetComm *m_netComm = nullptr;
};

class NetComm : public std::enable_shared_from_this<NetComm> {
public:
    /**
     * @功能描述：构造函数
     */
    NetComm();
    /**
     * @功能描述：构造函数（Server模式）
     */
    NetComm(std::shared_ptr<VmiSocket> newSocket, std::function<void(std::shared_ptr<NetComm>)> callback);
    /**
     * @功能描述：析构函数，释放对象
     */
    virtual ~NetComm();
    /**
     * @功能描述：设置异常断开回调函数
     */
    void SetBreakCallback(std::function<void(std::shared_ptr<NetComm>)> callback);
    /**
     * @功能描述：获取状态
     * @返回值：当前状态（未初始化/已初始化/运行态）
     */
    NetCommStatus GetStatus();
    /**
     * @功能描述：设置VmiSocket的状态
     * @参数 [in] status：要设置的socket状态，如断开
     */
    void SetSocketStatus(int status);
    /**
     * @功能描述：设置IP和端口
     * @参数 [in] ip：字符串形式的ip地址
     * @参数 [in] port：端口
     * @返回值：成功返回true，失败返回false
     */
    virtual bool SetIpAndPort(const std::string& ip, unsigned short port);
    /**
     * @功能描述：获取VmiSocket的连接状态
     * @返回值：如果连接着返回true，断开返回false
     */
    bool GetConnectStatus();
    /**
     * @功能描述：获取心跳模块记录的loopback平均延迟，反映网络传输状况
     * @返回值：loopback平均延迟
     */
    uint64_t GetLag();
    /**
     * @功能描述：初始化，根据Hook注册表创建各类型ServiceHandle
     * @返回值：成功返回true，失败返回false
     */
    virtual bool Init();
    /**
     * @功能描述：启动通信，启动解析线程和心跳
     * @返回值：成功返回true，失败返回false
     */
    virtual bool Start();
    /**
     * @功能描述：停止网络通信（加锁）
     */
    virtual void Stop();
    /**
     * @功能描述：清理、释放分配的对象和资源（加锁）
     */
    virtual void Deinit();
    /**
     * @功能描述：清空指定类型的消息队列
     * @参数 [in] type：消息类型
     */
    void ClearQueue(VMIMsgType type);
    /**
     * @功能描述：发送type类型的数据
     * @参数 [in] type：数据的消息类型
     * @参数 [in] dataPair：数据的地址和大小pair
     * @返回值：成功返回VMI_SUCCESS，失败返回错误码
     */
    uint32_t Send(VMIMsgType type, const std::pair<uint8_t *, uint32_t>& dataPair);
    /**
     * @功能描述：注册处理钩子
     * @参数 [in] type：消息类型
     * @参数 [in] hook：钩子函数地址
     * @参数 [in] isSingleFragment：是否单包发送（不分片）
     * @返回值：操作成功返回VMI_SUCCESS，失败返回VMI_INSTRUCTION_ENGINE_HOOK_REGISTER_FAIL
     */
    uint32_t RegisterHook(VMIMsgType type, RENDER_SERVER_HANDLE_HOOK hook, bool isSingleFragment);

#if defined(USE_GL_PACKET_HANDLE)
    /**
     * @功能描述：注册GL数据包处理钩子
     * @参数 [in] hook：GL钩子函数地址
     * @参数 [in] isSingleFragment：是否单包（不分片）
     * @返回值：操作成功返回VMI_SUCCESS，失败返回VMI_INSTRUCTION_ENGINE_HOOK_REGISTER_FAIL
     */
    uint32_t RegisterGLDataHook(RENDER_SERVER_HANDLE_HOOK hook, bool isSingleFragment);
#endif
    /**
     * @功能描述：处理SOCKET中断事件
     * @参数 [in] breakSocket：断开的VmiSocket对象
     */
    void HandleSocketBreak(std::shared_ptr<VmiSocket> breakSocket);
    /**
     * @功能描述：发送type类型的数据
     * @参数 [in] type：数据的消息类型
     * @参数 [in] pkt：StreamMsgHead包头引用，之后是数据
     * @参数 [in] dataSize：数据大小
     * @返回值：成功返回VMI_SUCCESS，失败返回错误码
     */
    uint32_t Send(VMIMsgType type, StreamMsgHead& pkt, uint32_t dataSize);
    /**
     * @功能描述：设置是否整包发送，不走分片流程
     * @参数 [in] type：数据类型
     * @参数 [in] flag：true表示无论数据多大都整包发送，否则false
     */
    void SetSingleFragment(VMIMsgType type, bool flag);
    /**
     * @功能描述：生成标识
     * @返回值：标识
     */
    uint32_t GenerateId();
    /**
     * @功能描述：获取标识
     * @返回值：标识
     */
    uint32_t GetId();
    /**
     * @功能描述：获取socket句柄
     * @返回值：socket句柄
     */
    int GetSocketFd();

private:
    /**
     * @功能描述：创建VmiSocket
     * @返回值：操作成功返回true，失败返回false
     */
    virtual bool CreateSocket();
    /**
     * @功能描述：启动解析线程和心跳
     * @返回值：成功返回true，失败返回false
     */
    bool StartStreamParseAndHeartbeat();
    /**
     * @功能描述：停止网络通信（不加锁），停止心跳、解析线程，关闭Socket
     */
    void StopNoLock();
    /**
     * @功能描述：清理、释放分配的对象和资源（不加锁）
     */
    void DeinitNoLock();
    /**
     * @功能描述：启动通信（Server模式）
     * @返回值：成功返回true，失败返回false
     */
    bool StartInServerMode();
    /**
     * @功能描述：启动通信（Client模式）
     * @返回值：成功返回true，失败返回false
     */
    bool StartInClientMode();

    static std::mutex g_idMutex;
    static uint32_t g_nextId;
    uint32_t m_id = 0;

    NetCommStatus m_status = NET_COMM_STATUS_UNINIT;
    std::string m_ip = "";
    unsigned short m_port = 0;
    std::mutex m_lock{};
    std::shared_ptr<VmiSocket> m_socket = nullptr;

    std::array<std::shared_ptr<PacketHandle>, VMIMsgType::End> m_pktHandle = {};
    std::shared_ptr<Heartbeat> m_heartbeat = nullptr;

    StreamParse *m_streamParser = nullptr;
    std::unique_ptr<StreamParseThread> m_streamParseThread = nullptr;

    std::array<MsgFragment, VMIMsgType::End> m_fragments = {};

    std::shared_ptr<ClientNotice> m_notice = nullptr;
    std::function<void(std::shared_ptr<NetComm>)> m_breakCallback = nullptr;
    bool m_isBroken = false;
    const int CLIENT = 0;
    const int SERVER = 1;
    int m_mode = 0;
};

/**
 * @功能描述：设置指令流的通信组件
 * @参数 [in] netComm：通信组件
 */
void SetInstructionStreamNetComm(std::shared_ptr<NetComm> netComm);
/**
 * @功能描述：设置视频流的通信组件
 * @参数 [in] netComm：通信组件
 */
void SetVideoStreamNetComm(std::shared_ptr<NetComm> netComm);
#endif
